/****************************************************************
 * description     :    saliency core algorithm
 * author          :    Wang Mingyin
 * time            :    July 15th ~ July 25th, 2013
 ****************************************************************/

#ifndef _SALIENCY_H_
#define _SALIENCY_H_ 


/***************************************************************************************
 *************      some useful macros, const values, pubilc structs     ***************
 ***************************************************************************************/
#define CLUSTER_SIZE                               16  //default 16clusters
#define GRID_SIZE                                  64 
#define HISTOGRAM_SIZE                             64 
#define HISTOGRAM_SIZE_PLUS_ONE                    65 //plus one to store the biggest element(65)
#define BAYES_BIN_COUNT_MAX                        100 //support yes or not feature, take the max value
#define FLOAT_MAX                                  3.402823466e+38F      // max positive value
#define FLOAT_MIN                                  1.175494351e-38F        // min positive value
#define EPSILON                                    0.00000000001 
#define BAYES_THRESHOLD                            0.999999
#define PI                                         3.14159265359 //what a tragedy!!!!!
#define DICT_SIZE                                  500
#define CODE_SIZE                                  512
#define IMAGE_PIXEL                                19200 //160 * 120
#define ONE_CHANNEL_IMAGE_MAX_PIXEL                25600 //max size 160 * 160
#define THREE_CHANNEL_IMAGE_MAX_PIXEL              76800 //160 * 160 * 3
#define IMAGE_MAX_GROUP                            25600
#define HORIZON_BLOCK                              8
#define VERTICAL_BLOCK                             8
#define MARGIN                                     15              //backdiff
#define FEATURE_NUMBER                             3 //shortpath, backdiff, yes or not
#define SHORTPATH_FEATURE_INDEX                    0
#define BACKDIFF_FEATURE_INDEX                     1
#define YON_FEATURE_INDEX                          2
#define ITERATE_NUMBER                             2 //in shortpath feature
#define SALIENCY_HAVE_THRESHOLD                    -1
//special case
#define YOU_FEATURE_BIN_COUNT                      100
#define NORMALIZE_LIMIT_RATE                       0.03

#define FILTER_WINDOW_SIZE                         5

#define WRITE_ALL_FLOAT_IMAGE                      0  // 0 means just write graphcut image, 1 means write all image.
#define YON_ROC_MASK                               0  // 0 means false, 1 means true
#define SHORTPATH_ROC_MASK                         0
#define BACKDIFF_ROC_MASK                          0

#ifndef MIN
#define MIN(a,b)  ((a) > (b) ? (b) : (a))
#endif

#ifndef MAX
#define MAX(a,b)  ((a) < (b) ? (b) : (a))
#endif

/* get reference to pixel at (col,row),
   for multi-channel images (col) should be multiplied by number of channels :IMAGE_ELEM(image, widthSteo, x * 3 + c, y) = value;	
   */
#define IMAGE_ELEM(image, elemtype, width_step, col, row)       \
    (((elemtype*)(image))[((width_step) * (row) + (col))])

/***************calculate image's step************************/
#define IPL_DEPTH_SIGN 0x80000000
/* default image row align (in bytes) */
#define  CV_DEFAULT_IMAGE_ROW_ALIGN  4
#define CALCULATE_STEP(width, cn, depth) (((((width) * (ch) * ((depth) &~ (IPL_DEPTH_SIGN)) + 7) / 8) + \
	(CV_DEFAULT_IMAGE_ROW_ALIGN) - 1) & (~((CV_DEFAULT_IMAGE_ROW_ALIGN) - 1)))
#define CALCULATE_STEP_THREE(width) (((((width) * (3) * ((8) &~ (IPL_DEPTH_SIGN)) + 7) / 8) + 3) & (~(3)))
//int img_width_step = (width* 3 * 8 + 31) / 32 * 4;

//the square distance between two colors
#define ColorSquDistance(clr1, clr2) ((clr1.r-clr2.r)*(clr1.r-clr2.r)+(clr1.g-clr2.g)*(clr1.g-clr2.g)+(clr1.b-clr2.b)*(clr1.b-clr2.b))

typedef struct ColorRGB {
	int r;
	int g;
	int b;
}ColorRGB;

typedef struct RGBCluster {
	float r;
	float g;
	float b;
}RGBCluster;


typedef struct ColorRange {
    float x_max;
    float x_min;
    float y_max;
    float y_min;
    float z_max;
    float z_min;
}ColorRange;

typedef struct WeakLearner {
	int index;
	float threshold;
	float conf1;
	float conf2;
}WeakLearner;

typedef struct BayesModel {
	float fore_hist[BAYES_BIN_COUNT_MAX];
    float back_hist[BAYES_BIN_COUNT_MAX];
    float fore_prob;
    float back_prob;
}BayesModel;

typedef struct SegPos {
	int x;
	int y;
	int width;
	int height;
} SegPos;

typedef struct IndexMap {
	int index_data[ONE_CHANNEL_IMAGE_MAX_PIXEL];
} IndexMap;


/******************************************************************************
                       ShortpathFeature
							aa bb cc
							dd ee ff
							gg hh ii
	   center by ee, calculate ee and other 8 directions distance
******************************************************************************/
void ShortpathFeature(unsigned char *img_data, float *result, int width, int height, int iter_num);

void BackDiffFeatureNew(unsigned char* clustermap, int width, int height, RGBCluster *cluster_values, int margin, float *backdiff_value);


//function parameter is two dimension array
int GetClassifyResult(double feature[][GRID_SIZE], double code_book[][GRID_SIZE], unsigned char *out_data, int width, int height);

void BayesClassifySimpleNew(BayesModel *bayes, int length, float *feature_shortpath, float *degree_shortpath, unsigned char *cluster_map, float *feature_backdiff, float *degree_backdiff,
						 float *feature_yon, float *result_back, int width, int height) ;

void BackDiffNormalizeNew(struct FloatCount *parray, int length, float rate);
void ShortPathNormalize(float *parray, int length, float rate);




//WeakLearner's relative operation
float Classify(WeakLearner *weak_learner, int weak_length, float *sample, int sample_length);
void Encoder(double *feature, float *code_result, double code_book[][GRID_SIZE], int length);

/********************************************************************************************************************
 * description     : determine whether there was saliency

 * img_data        : matrix data ptr(unsigned char*) (8 bits, 3 channels)
 * width           : the width of the image
 * height          : the height of the image
 * cd_data         : store the return, then to decide have saliency or not(float, 1 channel)
 * return value    : return the total number of saliency points
 *******************************************************************************************************************/
int SaliencyExist(unsigned char *img_data, unsigned char *label_img_data, int width, int height);

void ImageSegmentation(int width, int height, int hor_block, int ver_block, SegPos *seg_pos);

int SaliencyExistConfirm(unsigned char * AF_data, float *img_yon, int width, int height);
void GetXYZClusterInfoNew(unsigned char *img_data, int width, int height, float *xyz_data, unsigned char *out_data, RGBCluster *rgbcluster);
int SaliencyDetectionForRoc(unsigned char *img_data, unsigned char *label_img_data, int width, int height, unsigned char *graphcut, unsigned char *rough_data, unsigned char *AF_data);

void GetAFMap(BayesModel *bayes, int length, float *feature_shortpath, float *degree_shortpath, unsigned char *cluster_map, float *feature_backdiff, float *degree_backdiff,
						 float *result_back, float *result_fore, int width, int height);
void ConvertAFMap(float *result_fore, float *result_back, unsigned char *rough_data, int width, int height);

void GraphCutSegmentOld(unsigned char *img_data, int width, int height, float *fore_img, float *back_img, unsigned char *graphcut);
float Boundary(unsigned char *img_data, int width, int height, int x1, int y1, int x2, int y2);

void GetRoughBmpOld(float *result_fore, float *result_back, unsigned char *rough_data, int width, int height);

void InitGlobalDataFromFile();


/***************************************************************************************
 ****************            file related operation                 ********************
 ***************************************************************************************/
#define ROOT "./files/"
//#define CODE_BOOK_PATH                   ROOT##"origin_code.csv"
//#define BACKDIFF_DEGREE_PATH       ROOT##"cylinder_backdiff_statistics2.csv"
//#define BACKDIFF_BAYES_PATH          ROOT##"cylinder_bayes_backdiff2.csv"
//#define SHORTPATH_DEGREE_PATH   ROOT##"shortpath_after_medianfilter_statistics2.csv"
//#define SHORTPATH_BAYES_PATH      ROOT##"shortpath_bayes_after_medianfilter.csv"
//#define YON_BAYES_PATH                     ROOT##"yondistribution.csv"
//#define BOOST_DICTIONARY_PATH   ROOT##"dist_boost_dictionary_s.csv"

/***************************************************************************************
 ****************                       test                        ********************
 ***************************************************************************************/
//#define COLOR_SPACE                                      "HSV"
//#define COLOR_DIFF                                       "same"
//#define CODE_BOOK_PATH_TMP(n)                            ROOT##"codeBook_"##n##COLOR_SPACE##""##COLOR_DIFF##".csv" //codeBook_512HSVsame.csv
//#define CODE_PATH(num)                                   CODE_BOOK_PATH_TMP(#num)
//#define BOOST_DICTIONARY_PATH_TMP(n)                     ROOT##"dictFile"##n##COLOR_SPACE##""##COLOR_DIFF##".csv" //dictFile500HSVsame.csv
//#define BOOST_PATH(num)                                  BOOST_DICTIONARY_PATH_TMP(#num)
//#define YON_BAYES_PATH_TMP(n1, n2)                       ROOT##"Bayes"##n1##COLOR_SPACE##""##COLOR_DIFF##n2##".csv" //Bayes512HSVsame500.csv
//#define YON_PATH(n1, n2)                                 YON_BAYES_PATH_TMP(#n1, #n2)            
//#define CODE_BOOK_PATH_HELPER(CODE_SIZE)                 CODE_PATH(CODE_SIZE)
//#define CODE_BOOK_PATH                                   CODE_BOOK_PATH_HELPER(CODE_SIZE)
//#define BOOST_DICTIONARY_PATH_HELPER(DICT_SIZE)          BOOST_PATH(DICT_SIZE)
//#define BOOST_DICTIONARY_PATH                            BOOST_DICTIONARY_PATH_HELPER(DICT_SIZE)
//#define YON_BAYES_PATH_HELPER(CODE_SIZE, DICT_SIZE)      YON_PATH(CODE_SIZE, DICT_SIZE)
//#define YON_BAYES_PATH                                   YON_BAYES_PATH_HELPER(CODE_SIZE, DICT_SIZE)
//
//#define SHORTPATH_DEGREE_PATH                            ROOT##"ShortPathDegree64.csv"
//#define SHORTPATH_BAYES_PATH                             ROOT##"ShortPathBayes64.csv"
//#define BACKDIFF_DEGREE_PATH                             ROOT##"BackDiffDegree64.csv"
//#define BACKDIFF_BAYES_PATH                              ROOT##"BackDiffBayes64.csv"


#define COLOR_SPACE                                      "HSV"
#define COLOR_DIFF                                       "same"
#define CODE_BOOK_PATH_TMP(n)                            "./files/codeBook_512HSVsame.csv" //codeBook_512HSVsame.csv
#define CODE_PATH(num)                                   CODE_BOOK_PATH_TMP(#num)
#define BOOST_DICTIONARY_PATH_TMP(n)                     "./files/dictFile500HSVsame.csv" //dictFile500HSVsame.csv
#define BOOST_PATH(num)                                  BOOST_DICTIONARY_PATH_TMP(#num)
#define YON_BAYES_PATH_TMP(n1, n2)                       "./files/Bayes512HSVsame500.csv" //Bayes512HSVsame500.csv
#define YON_PATH(n1, n2)                                 YON_BAYES_PATH_TMP(#n1, #n2)            
#define CODE_BOOK_PATH_HELPER(CODE_SIZE)                 CODE_PATH(CODE_SIZE)
#define CODE_BOOK_PATH                                   CODE_BOOK_PATH_HELPER(CODE_SIZE)
#define BOOST_DICTIONARY_PATH_HELPER(DICT_SIZE)          BOOST_PATH(DICT_SIZE)
#define BOOST_DICTIONARY_PATH                            BOOST_DICTIONARY_PATH_HELPER(DICT_SIZE)
#define YON_BAYES_PATH_HELPER(CODE_SIZE, DICT_SIZE)      YON_PATH(CODE_SIZE, DICT_SIZE)
#define YON_BAYES_PATH                                   YON_BAYES_PATH_HELPER(CODE_SIZE, DICT_SIZE)

#define SHORTPATH_DEGREE_PATH                            "./files/ShortPathDegree64.csv"
#define SHORTPATH_BAYES_PATH                             "./files/ShortPathBayes64.csv"
#define BACKDIFF_DEGREE_PATH                             "./files/BackDiffDegree64.csv"
#define BACKDIFF_BAYES_PATH                              "./files/BackDiffBayes64.csv"



//code_book => CODE_SIZE * GRID_SIZE, need allocate space in the caller.
void ReadCodebook(const char *filename, double code_book[][GRID_SIZE]);
void ReadHistDegree(const char *filename, float *hist_degree);
void ReadBayesModel(const char *filename, BayesModel *bayes_model);
void ReadDictionary(char *filename, WeakLearner *weak_learner);


/********************************************************************************************************************
 * description        : (CountSort)the algorithm of count sort, only float type supported.

 * p                  : the pointer of the array(start from index 0)
 * length             : the length of the array
 * limit              : the cut size
 * min_v              : the result of the p[limit]
 * max_v              : the result of the p[length - limit]
 * example            : CountSort(ptmparray, length, limit, &min_v, &max_v);
 *******************************************************************************************************************/
struct FloatCount {
	float value;
	int count;
	int index;
};

void InsertionSort(struct FloatCount *first, struct FloatCount *last);
void CountSort(float *p, int length, int limit, float *min_v, float *max_v);

/********************************************************************************************************************
 * description        : the algorithm of heap sort, only float type supported.

 * p                  : the pointer of the array(start from index 0)
 * length             : the length of the array
 * limit              : the cut size
 * min_v              : the result of the p[limit]
 * max_v              : the result of the p[length - limit]
 * example            : CountSort(ptmparray, length, limit, &min_v, &max_v);
 *******************************************************************************************************************/
typedef int (*HeapCompare)(float, float);
#define MAX_LIMIT_LENGTH 768        // 160 * 160 * 0.03f
int MinHeapCom(float a, float b);
int MaxHeapCom(float a, float b);
void AdjustHeap(float *p, int hole_index, int len, HeapCompare cmp);
void MakeHeap(float *p, int length, HeapCompare cmp);
void SortHeap(float *p, int length, HeapCompare cmp);
float FindMaxOrMin(float *p, int length, HeapCompare cmp);

#define MAX_LENGTH 256


/******************************************************************************************
 **************************         write float image            **************************
 ******************************************************************************************/
void GetImageFloat(float *index_float, unsigned char *cluster_map, float *img_float, int width, int height);
void FloatToImage(float *img_float, int width, int height, unsigned char *img_data);
void SaveFloatImage(char *suffix, float *img_float, int width, int height);
void SaveYonImage(float *index_float, unsigned char *cluster_map, int width, int height);
void SaveShortpathImage(float *img_float, int width, int height);
void SaveBackdiffImage(float *index_float, unsigned char *cluster_map, int width, int height);
void SaveAFImage(unsigned char *img, int width, int height);
void SaveUcharImage(char *suffix, unsigned char *img, int width, int height);
void SaveRoughImage(unsigned char *img, int width, int height);

#endif //_SALIENCY_H_